package com.foruo.framework;

import com.foruo.framework.annotation.*;
import com.foruo.framework.entity.AnnotationEntity;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLDecoder;
import java.util.*;

/**
 * 注解获取工具类
 * @author GaoYuan
 * @date 2018/5/10 下午4:38
 */
public class AnnotationUtils {

    /**
     * 获取当前包路径下指定的Controller注解类型的文件
     * @param packageName 包名
     * @return 文件
     */
    public static List<Class<?>> getPackageController(String packageName, Class<? extends Annotation> annotation) {
        List<Class<?>> classList = new ArrayList<Class<?>>();
        String packageDirName = packageName.replace('.', '/');
        Enumeration<URL> dirs = null;

        //获取当前目录下面的所有的子目录的url
        try {
            dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
        } catch (IOException e) {
            e.printStackTrace();
        }

        while (dirs.hasMoreElements()) {
            URL url = dirs.nextElement();
            //得到当前url的类型
            String protocol = url.getProtocol();
            //如果当前类型是文件类型
            if ("file".equals(protocol)) {
                //获取包的物理路径
                String filePath = null;
                try {
                    filePath = URLDecoder.decode(url.getFile(), "UTF-8");
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
                if(!filePath.startsWith("/")){
                    filePath = filePath.substring(1);
                }

                getFilePathClasses(packageName,filePath,classList, annotation);
            }
        }


        return classList;
    }


    /**
     * 从指定的包下面找到文件名
     * @param packageName
     * @param filePath
     * @param classList
     * @param annotation 注解类型
     */
    private static void getFilePathClasses(String packageName,String filePath,List<Class<?>> classList, Class<? extends Annotation> annotation) {
        List<String> list = new ArrayList<>();
        try {
            list = getClassNameByFile(filePath, true);
        }catch (Exception e){
            e.printStackTrace();
        }
        for(String fileName:list){
            Class<?> classes = null;
            try {
                classes = Thread.currentThread().getContextClassLoader().loadClass(fileName);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            //判断该注解类型是不是所需要的类型
            if (null != classes && null != classes.getAnnotation(annotation)) {
                //把这个文件加入classlist中
                classList.add(classes);
            }
        }

    }

    /**
     * 根据class文件查找class类
     * @author GaoYuan
     * @date 2018/5/10 下午10:02
     */
    private static List<String> getClassNameByFile(String filePath, boolean childPackage) throws UnsupportedEncodingException {
        List<String> myClassName = new ArrayList<>();
        filePath = URLDecoder.decode(filePath, "UTF-8");
        File file = new File(filePath);
        File[] childFiles = file.listFiles();
        if (childFiles == null) {
            return myClassName;
        }
        for (File childFile : childFiles) {
            if (childFile.isDirectory()) {
                if (childPackage) {
                    myClassName.addAll(getClassNameByFile(childFile.getPath(), childPackage));
                }
            } else {
                String childFilePath = childFile.getPath();
                /**childFilePath = FileUtil.clearPath(childFilePath);*/
                if (childFilePath.endsWith(".class")) {
                    childFilePath = childFilePath.substring(childFilePath.indexOf("/classes/") + 9, childFilePath.lastIndexOf("."));
                    childFilePath = childFilePath.replace("/", ".");
                    myClassName.add(childFilePath);
                }
            }
        }
        return myClassName;
    }

    /**
     * 装载封装methodMap
     * @author GaoYuan
     * @date 2018/5/10 下午10:01
     */
    public static void setMethodMap(List<Class<?>> classList, Map<String,Map<String,AnnotationEntity>> methodMap) {

        Map<String,AnnotationEntity> getMap = new HashMap<>(16);
        Map<String,AnnotationEntity> getRestMap = new HashMap<>(16);
        Map<String,AnnotationEntity> postMap = new HashMap<>(16);
        Map<String,AnnotationEntity> postRestMap = new HashMap<>(16);

        for (Class classes : classList) {
            Controller classesMapping = (Controller)classes.getAnnotation(Controller.class);
            if(classesMapping!=null){
                //得到该类下面的所有方法
                Method[] methods = classes.getDeclaredMethods();

                for (Method method : methods) {

                    Get get = method.getAnnotation(Get.class);
                    if(get!=null){
                        getMap.put(classesMapping.value() + get.value(),new AnnotationEntity(classes,method));
                    }

                    GetRest getRest = method.getAnnotation(GetRest.class);
                    if(getRest!=null) {
                        getRestMap.put(classesMapping.value() + getRest.value(), new AnnotationEntity(classes,method));
                    }

                    Post post = method.getAnnotation(Post.class);
                    if(post!=null){
                        postMap.put(classesMapping.value() + post.value(),new AnnotationEntity(classes,method));
                    }

                    PostRest postRest = method.getAnnotation(PostRest.class);
                    if(postRest!=null) {
                        postRestMap.put(classesMapping.value() + postRest.value(), new AnnotationEntity(classes,method));
                    }
                }
            }
        }
        methodMap.put(Get.class.getName(),getMap);
        methodMap.put(GetRest.class.getName(),getRestMap);
        methodMap.put(Post.class.getName(),postMap);
        methodMap.put(PostRest.class.getName(),postRestMap);
    }


}
